
package com.shop.cloud.mall.admin.service.impl;

import cn.binarywang.wx.miniapp.bean.shop.request.shipping.OrderKeyBean;
import cn.binarywang.wx.miniapp.bean.shop.request.shipping.PayerBean;
import cn.binarywang.wx.miniapp.bean.shop.request.shipping.ShippingListBean;
import cn.binarywang.wx.miniapp.bean.shop.request.shipping.WxMaOrderShippingInfoUploadRequest;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.shop.cloud.common.core.constant.CacheConstants;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.core.util.LocalDateTimeUtils;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.security.entity.BaseUser;
import com.shop.cloud.common.security.util.SecurityUtils;
import com.shop.cloud.mall.admin.mapper.*;
import com.shop.cloud.mall.admin.service.*;
import com.shop.cloud.mall.common.config.MallConfigProperties;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.dto.OrderDeliveryDTO;
import com.shop.cloud.mall.common.dto.PlaceOrderDTO;
import com.shop.cloud.mall.common.dto.PlaceOrderSkuDTO;
import com.shop.cloud.mall.common.entity.*;
import com.shop.cloud.mall.common.enums.OrderItemEnum;
import com.shop.cloud.mall.common.enums.OrderLogisticsEnum;
import com.shop.cloud.mall.common.enums.OrderInfoEnum;
import com.shop.cloud.mall.common.feign.FeignOrderInfoApiService;
import com.shop.cloud.pay.common.constant.PayConstants;
import com.shop.cloud.pay.common.dto.AliBaseRequest;
import com.shop.cloud.pay.common.feign.FeignPayService;
import com.shop.cloud.weixin.common.entity.WxUser;
import com.shop.cloud.weixin.common.feign.FeignWxMaOrderShippingService;
import com.shop.cloud.weixin.common.feign.FeignWxTemplateMsgService;
import com.shop.cloud.weixin.common.constant.WxConstant;
import com.shop.cloud.weixin.common.dto.WxTemplateMsgSendDTO;
import com.shop.cloud.weixin.common.feign.FeignWxUserService;
import com.kuaidi100.sdk.api.LabelV2;
import com.kuaidi100.sdk.api.Subscribe;
import com.kuaidi100.sdk.contant.ApiInfoConstant;
import com.kuaidi100.sdk.contant.PrintType;
import com.kuaidi100.sdk.core.IBaseClient;
import com.kuaidi100.sdk.pojo.HttpResult;
import com.kuaidi100.sdk.request.*;
import com.kuaidi100.sdk.request.labelV2.OrderReq;
import com.kuaidi100.sdk.utils.SignUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.klock.annotation.Klock;
import org.springframework.boot.autoconfigure.klock.model.LockTimeoutStrategy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 商城订单
 *
 * @author
 * @date 2019-09-10 15:21:22
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

	private final OrderItemService orderItemService;
	private final OrderLogisticsService orderLogisticsService;
	private final RedisTemplate<String, String> redisTemplate;
	private final MallConfigProperties mallConfigProperties;
	private final FeignWxTemplateMsgService feignWxTemplateMsgService;
	private final OrderLogisticsDetailService orderLogisticsDetailService;
	private final ConfigLogisticsService configLogisticsService;
	private final ShopLogisticsAccountService shopLogisticsAccountService;
	private final SupplierLogisticsAccountService supplierLogisticsAccountService;
	private final GoodsSkuMapper goodsSkuMapper;
	private final GoodsSkuService goodsSkuService;
	private final GoodsSkuSpecValueMapper goodsSkuSpecValueMapper;
	private final GoodsSpuService goodsSpuService;
	private final ShopInfoService shopInfoService;
	private final FeignPayService feignPayService;
	private final FeignWxMaOrderShippingService feignWxMaOrderShippingService;
	private final FeignWxUserService feignWxUserService;
	private final FeignOrderInfoApiService feignOrderInfoApiService;

	@SneakyThrows
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delivery(OrderDeliveryDTO orderDeliveryDTO) {
		OrderInfo orderInfo = baseMapper.selectById(orderDeliveryDTO.getOrderId());
		OrderLogistics orderLogistics = new OrderLogistics();
		orderLogistics.setId(orderDeliveryDTO.getOrderLogisticsId());
		orderLogistics.setRecName(orderDeliveryDTO.getRecName());
		orderLogistics.setRecTel(orderDeliveryDTO.getRecTel());
		orderLogistics.setRecAddress(orderDeliveryDTO.getRecAddress());
		orderLogistics.setOrderId(orderDeliveryDTO.getOrderId());
		OrderItem orderItem = new OrderItem();
		orderItem.setDeliveryTime(LocalDateTime.now());
		orderItem.setDeliveryType(orderDeliveryDTO.getDeliveryType());
		//修改发货则重置该订单物流id绑定的订单详情
		if(StrUtil.isNotBlank(orderLogistics.getId())){
			orderItemService.update(new UpdateWrapper<OrderItem>().lambda()
					.set(OrderItem::getLogisticsId,null)
					.eq(OrderItem::getLogisticsId,orderLogistics.getId()));
		}
		if(MallConstants.DELIVERY_TYPE_1.equals(orderDeliveryDTO.getDeliveryType())){//发物流
			ConfigLogistics configLogistics = configLogisticsService.getOne();
			//调快递100自动获取电子面单
			if(MallConstants.LABEL_WAY_2.equals(orderDeliveryDTO.getLabelWay())){
				//收货人
				ManInfo recManInfo  = new ManInfo();
				recManInfo.setName(orderLogistics.getRecName());
				recManInfo.setMobile(orderLogistics.getRecTel());
				recManInfo.setPrintAddr(orderLogistics.getRecAddress());
				//寄件人，取店铺里的信息
				ManInfo sendManInfo = new ManInfo();
				sendManInfo.setName(orderDeliveryDTO.getSendName());
				sendManInfo.setMobile(orderDeliveryDTO.getSendTel());
				sendManInfo.setPrintAddr(orderDeliveryDTO.getSendAddress());

				OrderReq orderReq = new OrderReq();
				orderReq.setKuaidicom(orderDeliveryDTO.getLogisticsCode());
				orderReq.setCount(1);
				orderReq.setTempId(orderDeliveryDTO.getLabelTemplateId());
				orderReq.setSendMan(sendManInfo);
				orderReq.setRecMan(recManInfo);
				if(orderDeliveryDTO.getWeight() != null){
					orderReq.setWeight(orderDeliveryDTO.getWeight().doubleValue());
				}
				orderReq.setCargo(StrUtil.subWithLength(orderInfo.getName(), 0, 20));
				orderReq.setPrintType(PrintType.HTML);
				//获取物流月结账号
				BaseUser baseUser = SecurityUtils.getUser();
				//供应商账号则查询供应商物流账号
				if(CommonConstants.USER_TYPE_3.equals(baseUser.getType())){
					SupplierLogisticsAccount supplierLogisticsAccount = supplierLogisticsAccountService.getById(orderDeliveryDTO.getShopLogisticsAccountId());
					orderReq.setPartnerId(supplierLogisticsAccount.getAccountId());
					orderReq.setPartnerKey(supplierLogisticsAccount.getAccountKey());
					orderReq.setNet(supplierLogisticsAccount.getNet());
					orderReq.setCode(supplierLogisticsAccount.getCode());
				}else{
					ShopLogisticsAccount shopLogisticsAccount = shopLogisticsAccountService.getById(orderDeliveryDTO.getShopLogisticsAccountId());
					orderReq.setPartnerId(shopLogisticsAccount.getAccountId());
					orderReq.setPartnerKey(shopLogisticsAccount.getAccountKey());
					orderReq.setNet(shopLogisticsAccount.getNet());
					orderReq.setCode(shopLogisticsAccount.getCode());
				}

				String param = JSONUtil.toJsonStr(orderReq);
				String t = System.currentTimeMillis() + "";

				PrintReq printReq = new PrintReq();
				printReq.setT(t);
				printReq.setKey(configLogistics.getLogisticsKey());
				printReq.setSign(SignUtils.printSign(param,t,configLogistics.getLogisticsKey(),configLogistics.getLogisticsSecret()));
				printReq.setMethod(ApiInfoConstant.ORDER);
				printReq.setParam(param);

				IBaseClient baseClient = new LabelV2();
				HttpResult httpResult = baseClient.execute(printReq);
				if(httpResult.getStatus() == 200){
					JSONObject jSONObject = JSONUtil.parseObj(httpResult.getBody());
					if(jSONObject.getInt("code") == 200 && jSONObject.getBool("success")){
						JSONObject data = jSONObject.getJSONObject("data");
						//获取快递单号
						orderDeliveryDTO.setLogisticsNo(data.getStr("kuaidinum"));
						orderLogistics.setLabelUrl(data.getStr("label"));
					}else{
						throw new RuntimeException(jSONObject.getStr("message"));
					}
				}else{
					throw new RuntimeException(httpResult.getError());
				}
			}
			orderLogistics.setLabelWay(orderDeliveryDTO.getLabelWay());
			orderLogistics.setLogisticsCode(orderDeliveryDTO.getLogisticsCode());
			orderLogistics.setLogisticsNo(orderDeliveryDTO.getLogisticsNo());
			orderLogistics.setStatus(OrderLogisticsEnum.STATUS_1.getValue());
			configLogistics.getLogisticsCompany().forEach(logistics -> {
				JSONObject jsLogistics = JSONUtil.parseObj(logistics);
				if(StrUtil.equals(jsLogistics.get("code").toString(), orderDeliveryDTO.getLogisticsCode())){
					orderLogistics.setLogisticsName(jsLogistics.get("name").toString());
				}
			});
			orderLogisticsService.saveOrUpdate(orderLogistics);
			orderLogisticsDetailService.remove(Wrappers.<OrderLogisticsDetail>lambdaQuery()
					.eq(OrderLogisticsDetail::getLogisticsId,orderLogistics.getId()));//删除旧的物流路由
			//订单详情更新订单物流ID
			orderItem.setLogisticsId(orderLogistics.getId());

			//订阅快递100：https://gitee.com/kuaidi100-api/java-demo
			String callbackurl = StrUtil.format("{}{}{}{}{}", mallConfigProperties.getNotifyHost(),
					MallConstants.SERVER_ROUTE_NAME_MALLAPI,
					MallConstants.ORDER_LOGISTICSR_NOTIFY_URL,
					"?tenantId=",
					orderInfo.getTenantId());//回调地址
			SubscribeParameters subscribeParameters = new SubscribeParameters();
			subscribeParameters.setCallbackurl(callbackurl);
			subscribeParameters.setPhone(orderLogistics.getRecTel());

			SubscribeParam subscribeParam = new SubscribeParam();
			subscribeParam.setParameters(subscribeParameters);
			subscribeParam.setCompany(orderDeliveryDTO.getLogisticsCode());
			subscribeParam.setNumber(orderDeliveryDTO.getLogisticsNo());
			subscribeParam.setKey(configLogistics.getLogisticsKey());

			SubscribeReq subscribeReq = new SubscribeReq();
			subscribeReq.setSchema(ApiInfoConstant.SUBSCRIBE_SCHEMA);
			subscribeReq.setParam(JSONUtil.toJsonStr(subscribeParam));

			IBaseClient subscribe = new Subscribe();
			HttpResult httpResult = subscribe.execute(subscribeReq);
			if(httpResult.getStatus() == 200){
				JSONObject jSONObject = JSONUtil.parseObj(httpResult.getBody());
				if(!"200".equals(jSONObject.get("returnCode"))){
					throw new RuntimeException(jSONObject.getStr("message"));
				}
			}else{
				throw new RuntimeException(httpResult.getError());
			}
		}
		//更新订单详情
		orderItemService.update(orderItem,Wrappers.<OrderItem>lambdaQuery().in(OrderItem::getId, Convert.toList(orderDeliveryDTO.getOrderItemIds())));
		//查询该订单的所有订单详情
		List<OrderItem> listOrderItem = orderItemService.list(Wrappers.<OrderItem>query().lambda()
				.eq(OrderItem::getOrderId, orderInfo.getId())
				.isNull(OrderItem::getDeliveryType));
		//订单详情已全部发货完成，完成则更新订单状态、加入自动确认收货
		if(listOrderItem.size() == 0){
			//更新订单状态
			orderInfo.setStatus(OrderInfoEnum.STATUS_2.getValue());
			//加入redis，7天后自动确认收货
			String keyRedis = String.valueOf(StrUtil.format("{}:{}::{}", TenantContextHolder.getTenantId(), CacheConstants.MALL_ORDER_KEY_STATUS_2, orderInfo.getId()));
			redisTemplate.opsForValue().set(keyRedis, orderInfo.getOrderNo() , MallConstants.ORDER_TIME_OUT_2, TimeUnit.DAYS);//设置过期时间
		}else{
			//订单详情未全部发货完成，判断未发货的订单详情是否已全部退款，是则更新订单状态、加入自动确认收货
			int i = listOrderItem.stream()
					.filter(obj -> CommonConstants.YES.equals(obj.getIsRefund())).collect(Collectors.toList()).size();
			if(i == listOrderItem.size()){
				//更新订单状态
				orderInfo.setStatus(OrderInfoEnum.STATUS_2.getValue());
				//加入redis，7天后自动确认收货
				String keyRedis = String.valueOf(StrUtil.format("{}:{}::{}", TenantContextHolder.getTenantId(), CacheConstants.MALL_ORDER_KEY_STATUS_2, orderInfo.getId()));
				redisTemplate.opsForValue().set(keyRedis, orderInfo.getOrderNo() , MallConstants.ORDER_TIME_OUT_2, TimeUnit.DAYS);//设置过期时间
			}
		}
		//发送微信订阅、模板消息
		try {
			WxTemplateMsgSendDTO wxTemplateMsgSendDTO = new WxTemplateMsgSendDTO();
			wxTemplateMsgSendDTO.setMallUserId(orderInfo.getUserId());
			wxTemplateMsgSendDTO.setUseType(WxConstant.WX_TMP_USE_TYPE_3);
			wxTemplateMsgSendDTO.setPage("pages/order/order-detail/index?id="+orderInfo.getId());
			Map<String, Object> data = new HashMap();
			Map<String, Object> map = BeanUtil.beanToMap(orderInfo);
			for(String mapKey: map.keySet()){
				data.put("order." + mapKey, map.get(mapKey));
			}
			if(orderLogistics != null){
				Map<String, Object> map2 = BeanUtil.beanToMap(orderLogistics);
				for(String mapKey: map2.keySet()){
					data.put("orderLogistics." + mapKey, map2.get(mapKey));
				}
			}
			wxTemplateMsgSendDTO.setData(data);
			feignWxTemplateMsgService.sendTemplateMsgMa(wxTemplateMsgSendDTO, SecurityConstants.FROM_IN);
			feignWxTemplateMsgService.sendTemplateMsgMp(wxTemplateMsgSendDTO, SecurityConstants.FROM_IN);
		}catch (Exception e){
			log.error("发送微信订阅、模板消息出错："+e.getMessage(), e);
		}
		super.updateById(orderInfo);
		if(MallConstants.CLIENT_TYPE_MA.equals(orderInfo.getAppType())){
			//对接小程序发货信息
			this.wxMaOrderShippingUpload(orderInfo);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void takeGoods(String id) {
		OrderInfo orderInfo = this.getById(id);
		if(MallConstants.CLIENT_TYPE_MA.equals(orderInfo.getAppType())){
			//对接小程序发货信息
			this.wxMaOrderShippingUpload(orderInfo);
		}

		R r = feignOrderInfoApiService.orderTakeGoodsInside(id, SecurityConstants.FROM_IN);
		if(!r.isOk()){
			throw new RuntimeException(r.getMsg());
		}
	}

	/**
	 * 对接小程序发货信息
	 * @param orderInfo
	 */
	public void wxMaOrderShippingUpload(OrderInfo orderInfo){
		//对接小程序发货信息，不想把实际数据传给腾讯，并缩短资金回笼周期，所以直接传虚拟发货
		OrderKeyBean orderKeyBean = new OrderKeyBean();
		orderKeyBean.setOrderNumberType(2);
		orderKeyBean.setTransactionId(orderInfo.getTransactionId());
		List<ShippingListBean> shippingList = new ArrayList<>();
		ShippingListBean shippingListBean = new ShippingListBean();
		String body = orderInfo.getName();
		body = body.length() > 40 ? body.substring(0,39) : body;
		shippingListBean.setItemDesc(body);
		shippingList.add(shippingListBean);
		PayerBean payer = new PayerBean();
		WxUser wxUser = feignWxUserService.getByMallUserId(orderInfo.getUserId(), orderInfo.getAppId(), SecurityConstants.FROM_IN).getData();
		if(wxUser != null){
			payer.setOpenid(wxUser.getOpenId());
			WxMaOrderShippingInfoUploadRequest request = new WxMaOrderShippingInfoUploadRequest();
			request.setOrderKey(orderKeyBean);
			request.setShippingList(shippingList);
			request.setPayer(payer);
			request.setLogisticsType(3);
			request.setDeliveryMode(1);
			if(MallConstants.DELIVERY_WAY_2.equals(orderInfo.getDeliveryWay())){
				request.setLogisticsType(4);
			}
			request.setUploadTime(DateUtil.format(new Date(),"yyyy-MM-dd'T'HH:mm:ssXXX"));
			feignWxMaOrderShippingService.upload(orderInfo.getAppId(), request, SecurityConstants.FROM_IN);
		}
	}

	@Override
	public IPage<OrderInfo> page2(IPage<OrderInfo> page, Wrapper<OrderInfo> queryWrapper, String supplierId) {
		return baseMapper.selectPage2(page,queryWrapper.getEntity(), supplierId);
	}

	@Override
	public IPage<OrderInfo> page1(IPage<OrderInfo> page, Wrapper<OrderInfo> queryWrapper) {
		return baseMapper.selectPage1(page,queryWrapper.getEntity());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean removeById(Serializable id) {
		orderItemService.remove(Wrappers.<OrderItem>lambdaQuery()
				.eq(OrderItem::getOrderId,id));//删除订单详情
		return super.removeById(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void editPrice(OrderItem orderItem) {
		BigDecimal editPrice = orderItem.getPaymentPrice();
		orderItem = orderItemService.getById(orderItem.getId());
		BigDecimal oldPrice = orderItem.getPaymentPrice();
		orderItem.setPaymentPrice(editPrice);
		OrderInfo orderInfo = baseMapper.selectById(orderItem.getOrderId());
		orderInfo.setPaymentPrice(orderInfo.getPaymentPrice().add(editPrice.subtract(oldPrice)));
		orderItemService.updateById(orderItem);
		orderInfo.setOrderNo(IdUtil.getSnowflake(0,0).nextIdStr());
		baseMapper.updateById(orderInfo);
	}

	@Override
	public BigDecimal sumPaymentPrice(OrderInfo orderInfo) {
		return baseMapper.sumPaymentPrice(orderInfo);
	}

	@Override
	public OrderInfo getById1(Serializable id) {
		return baseMapper.selectById1(id);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public OrderInfo orderAddCashier(HttpServletRequest request, PlaceOrderDTO placeOrderDTO) {
		placeOrderDTO.setUserId(SecurityUtils.getUser().getId());
		placeOrderDTO.setAppType(MallConstants.CLIENT_TYPE_UI);
		Map<String, PlaceOrderSkuDTO> mapSkuDTO = placeOrderDTO.getSkus().stream().collect(Collectors.toMap(PlaceOrderSkuDTO::getSkuId, Function.identity()));
		//查询出所有sku信息
		List<GoodsSku> listSku = goodsSkuMapper.listSkuInOrderSub(placeOrderDTO.getShopId(), placeOrderDTO.getSkus());
		OrderInfo orderInfo = new OrderInfo();
		BeanUtil.copyProperties(placeOrderDTO,orderInfo);
		orderInfo.setPaymentWay(MallConstants.PAYMENT_WAY_2);
		orderInfo.setShopId(placeOrderDTO.getShopId());
		orderInfo.setIsPay(CommonConstants.NO);
		orderInfo.setOrderNo(IdUtil.getSnowflake(0,0).nextIdStr());
		orderInfo.setSalesPrice(BigDecimal.ZERO);
		orderInfo.setPaymentPrice(BigDecimal.ZERO);
		orderInfo.setCreateTime(LocalDateTime.now());
		List<OrderItem> listOrderItem = new ArrayList<>();
		List<GoodsSku> listGoodsSku = new ArrayList<>();
		listSku.forEach(goodsSku -> {
			PlaceOrderSkuDTO placeOrderSkuDTO  = mapSkuDTO.get(goodsSku.getId());
			if(placeOrderSkuDTO == null){
				throw new RuntimeException("参数错误");
			}
			if(goodsSku != null){
				GoodsSpu goodsSpu = goodsSku.getGoodsSpu();
				if(goodsSpu != null){
					OrderItem orderItem = new OrderItem();
					orderItem.setOrderId(orderInfo.getId());
					orderItem.setShopId(orderInfo.getShopId());
					orderItem.setStatus(OrderItemEnum.STATUS_0.getValue());
					orderItem.setIsRefund(CommonConstants.NO);
					orderItem.setSpuId(goodsSpu.getId());
					orderItem.setSkuId(goodsSku.getId());
					orderItem.setSpuName(goodsSpu.getName());
					orderItem.setPicUrl(StrUtil.isNotBlank(goodsSku.getPicUrl()) ? goodsSku.getPicUrl() : goodsSpu.getPicUrls()[0]);
					orderItem.setQuantity(placeOrderSkuDTO.getQuantity());
					orderItem.setSalesPrice(goodsSku.getSalesPrice());
					orderItem.setPaymentPrice(placeOrderSkuDTO.getPaymentPrice());
					BigDecimal quantity = new BigDecimal(placeOrderSkuDTO.getQuantity());
					List<GoodsSkuSpecValue> listGoodsSkuSpecValue = goodsSkuSpecValueMapper.listGoodsSkuSpecValueBySkuId(goodsSku.getId());
					listGoodsSkuSpecValue.forEach(goodsSkuSpecValue -> {
						String specInfo = orderItem.getSpecInfo();
						specInfo = StrUtil.isNotBlank(specInfo) ? specInfo : "";
						orderItem.setSpecInfo(specInfo
								+ goodsSkuSpecValue.getSpecValueName()
								+  "，" );
					});
					String specInfo = orderItem.getSpecInfo();
					if(StrUtil.isNotBlank(specInfo)){
						orderItem.setSpecInfo(specInfo.substring(0,specInfo.length() - 1));
					}
					listOrderItem.add(orderItem);
					orderInfo.setSalesPrice(orderInfo.getSalesPrice().add(goodsSku.getSalesPrice().multiply(quantity)));
					orderInfo.setPaymentPrice(orderInfo.getPaymentPrice().add(orderItem.getPaymentPrice()));
					goodsSku.setStock(goodsSku.getStock() - orderItem.getQuantity());
					listGoodsSku.add(goodsSku);
				}
			}
		});
		if(listOrderItem.size() > 0 && listGoodsSku.size()>0){
			orderInfo.setName(listOrderItem.get(0).getSpuName());
			super.save(orderInfo);//保存订单
			listOrderItem.forEach(orderItem -> orderItem.setOrderId(orderInfo.getId()));
			//保存订单详情
			orderItemService.saveBatch(listOrderItem);
			listGoodsSku.forEach(goodsSkuItem -> {
				if(!goodsSkuService.updateById(goodsSkuItem)){//更新库存
					throw new RuntimeException("请重新提交");
				}
			});

		}
		return orderInfo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void orderCancelCashier(OrderInfo orderInfo) {
		if(CommonConstants.NO.equals(orderInfo.getIsPay()) && !OrderInfoEnum.STATUS_5.getValue().equals(orderInfo.getStatus())){//校验
			//实时查询订单是否已支付
			WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
			ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
			if(shopInfo != null){
				//微信支付
				if(StrUtil.isNotBlank(shopInfo.getWxMchId())){
					request.setTransactionId(orderInfo.getTransactionId());
					request.setOutTradeNo(orderInfo.getOrderNo());
					request.setSubMchId(shopInfo.getWxMchId());
					R<WxPayOrderQueryResult> r = feignPayService.queryOrderWx(request, SecurityConstants.FROM_IN);
					if(r.isOk()){
						WxPayOrderQueryResult wxPayOrderQueryResult = r.getData();
						if(!WxPayConstants.WxpayTradeStatus.NOTPAY.equals(wxPayOrderQueryResult.getTradeState())){//只有未支付的订单能取消，已支付订单完成回调逻辑
							orderInfo.setTradeType(wxPayOrderQueryResult.getTradeType());
							if(orderInfo.getPaymentPrice().multiply(new BigDecimal(100)).intValue() == wxPayOrderQueryResult.getTotalFee()){
								String timeEnd = wxPayOrderQueryResult.getTimeEnd();
								LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
								orderInfo.setPaymentTime(paymentTime);
								orderInfo.setTransactionId(wxPayOrderQueryResult.getTransactionId());
								orderInfo.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_1);
								this.notifyOrderCashier(orderInfo);
							}else{
								throw new RuntimeException("该订单已支付，付款金额与订单金额不等");
							}
						}
					}
				}
				//支付宝
				if(StrUtil.isNotBlank(shopInfo.getAliAuthToken())){
					AliBaseRequest aliBaseRequest = new AliBaseRequest();
					Map<String, Object> params = new HashMap<>();
					params.put("outTradeNo",orderInfo.getOrderNo());
					aliBaseRequest.setAppAuthToken(shopInfo.getAliAuthToken());
					aliBaseRequest.setParams(params);
					R<AlipayTradeQueryResponse> r = feignPayService.queryOrderAli(aliBaseRequest, SecurityConstants.FROM_IN);
					if(r.isOk()){
						AlipayTradeQueryResponse alipayTradeQueryResponse = r.getData();
						if(PayConstants.ALI_RES_CODE_SUCCESS.equals(alipayTradeQueryResponse.getCode())
								&& ("TRADE_SUCCESS".equals(alipayTradeQueryResponse.getTradeStatus())
								||"TRADE_FINISHED".equals(alipayTradeQueryResponse.getTradeStatus()))){//只有未支付的订单能取消，已支付订单完成回调逻辑
							if(orderInfo.getPaymentPrice().compareTo(new BigDecimal(alipayTradeQueryResponse.getTotalAmount())) == 0){
								LocalDateTime paymentTime = LocalDateTimeUtils.parse(alipayTradeQueryResponse.getSendPayDate());
								orderInfo.setPaymentTime(paymentTime);
								orderInfo.setTransactionId(alipayTradeQueryResponse.getTradeNo());
								orderInfo.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_2);
								this.notifyOrderCashier(orderInfo);
							}else{
								throw new RuntimeException("该订单已支付，付款金额与订单金额不等");
							}
						}
					}
				}
			}
			orderInfo.setStatus(OrderInfoEnum.STATUS_5.getValue());
			//回滚库存
			List<OrderItem> listOrderItem = orderItemService.list(Wrappers.<OrderItem>lambdaQuery()
					.eq(OrderItem::getOrderId,orderInfo.getId()));
			listOrderItem.forEach(orderItem -> {
				GoodsSku goodsSku = goodsSkuMapper.selectById(orderItem.getSkuId());
				if(goodsSku != null){
					goodsSku.setStock(goodsSku.getStock() + orderItem.getQuantity());
					if(!goodsSkuService.updateById(goodsSku)){//更新库存
						throw new RuntimeException("请重新提交");
					}
				}
			});
			baseMapper.updateById(orderInfo);
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	//加锁防止支付平台同时发多次回调
	@Klock(name = "notifyOrder", keys = {"#orderInfo.getId()"}, lockTimeoutStrategy = LockTimeoutStrategy.FAIL_FAST)
	public void notifyOrderCashier(OrderInfo orderInfo) {
		if(CommonConstants.NO.equals(orderInfo.getIsPay())){//只有未支付订单能操作
			orderInfo.setIsPay(CommonConstants.YES);
			orderInfo.setStatus(OrderInfoEnum.STATUS_3.getValue());
			List<OrderItem> listOrderItem = orderItemService.list(Wrappers.<OrderItem>lambdaQuery()
					.eq(OrderItem::getOrderId,orderInfo.getId()));
			Map<String, List<OrderItem>> resultList = listOrderItem.stream().collect(Collectors.groupingBy(OrderItem::getSpuId));
			List<GoodsSpu> listGoodsSpu = goodsSpuService.listByIds(resultList.keySet());
			listGoodsSpu.forEach(goodsSpu -> {
				resultList.get(goodsSpu.getId()).forEach(orderItem -> {
					//更新销量
					goodsSpu.setSaleNum(goodsSpu.getSaleNum()+orderItem.getQuantity());
				});
				goodsSpuService.updateById2(goodsSpu);
			});
			baseMapper.updateById(orderInfo);//更新订单
		}
	}
}
